#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include "param.h"
#include "types.h"
#include "defs.h"

DIR *i_dirp, *o_dirp;
int i_dirfd, o_dirfd;
pthread_mutex_t fmtx;

int
file_init (char *i_dir_name, char *o_dir_name) {
    if ((i_dirp = opendir (i_dir_name)) == NULL) 
        HANDLE_ERROR ("file_init", "opendir (in)",1);
    if ((o_dirp = opendir (o_dir_name)) == NULL)
        HANDLE_ERROR ("file_init", "opendir (out)",1);
    if ((i_dirfd = dirfd (i_dirp)) == -1)
        HANDLE_ERROR ("file_init", "dirfd (in)",1);
    if ((o_dirfd = dirfd (o_dirp)) == -1)
        HANDLE_ERROR ("file_init", "dirfd (out)",1);
    if (pthread_mutex_init (&fmtx, NULL) == -1)
        HANDLE_ERROR ("file_init", "fmtx",1);
    return 0;
    error:
    return -1;
}

/* 返回下一个in fd，若无可用，则返回-1 */
int
file_get_in_fd () {
    int fd;
    struct dirent *dirtp;
    LOCK (fmtx);
    next_item:
    errno = 0;
    if ((dirtp = readdir (i_dirp)) == NULL) {
        if (errno != 0)
        HANDLE_ERROR ("file_get_in_fd", "readdir",1);
        goto finish;
    }
    if (dirtp->d_type != DT_REG) 
        goto next_item;
    if (faccessat (i_dirfd, dirtp->d_name,
        F_OK | R_OK | W_OK, AT_EACCESS) == -1)
        HANDLE_ERROR ("file_get_in_fd", "faccessat",1);
    if ((fd = openat (i_dirfd, dirtp->d_name,O_RDONLY)) == -1)
        HANDLE_ERROR ("file_get_in_fd", "openat",1);
    UNLOCK (fmtx);
    return fd;
    finish:
    UNLOCK (fmtx);
    return -1;
    error:
    UNLOCK (fmtx);
    return -1;
}

/* 返回下一个out fd，若无可用，则返回-1 */
int
file_get_out_fd () {
    int fd;
    char *file_name;
    LOCK (fmtx);
    file_name = get_rand_name ();
    while (faccessat (o_dirfd,file_name,F_OK,AT_EACCESS) != -1) {
        printf ("faccessat: outfile %s already exists.\n", file_name);
        free (file_name);
        file_name = get_rand_name ();
    }
    if ((fd = openat (o_dirfd, file_name, 
        O_TRUNC|O_CREAT|O_RDWR, S_IRUSR | S_IWUSR)) == -1)
    HANDLE_ERROR ("file_get_out_fd","openat",1);
    free (file_name);
    UNLOCK (fmtx);
    return fd;
    error:
    free (file_name);
    UNLOCK (fmtx);
    return -1;
}

int
file_clean () {
    closedir (i_dirp);
    closedir (o_dirp);
    pthread_mutex_destroy (&fmtx);
    return 0;
}